using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace HandyIRCChat
{
    public partial class MainForm : Form
    {
        #region Declarations

        internal HandyLogic handyLogic = HandyLogic.CreateInstance();

        private Thread connectThread;

        private delegate void AddUserDelegate(string channel, string name);

        private delegate void RemoveUserDelegate(string name);

        private delegate void JoinChannelDelegate(string channelName);

        private delegate void LeaveChannelDelegate(string channelName);

        private delegate void ShowChannelFormDelegate(string channelName);

        private delegate void ShowPrivateFormDelegate(string userName);

        private delegate void RenameUserDelegate(string oldName, string newName);

        #endregion

        #region c'tor

        public MainForm()
        {
            InitializeComponent();
            CustomInitialize();

            handyLogic.JoinChannelEvent += 
                new HandyLogic.JoinChannelEventHandler(handyLogic_JoinChannelEvent);
            handyLogic.LeaveChannelEvent += 
                new HandyLogic.LeaveChannelEventHandler(handyLogic_LeaveChannelEvent);
            handyLogic.UserJoinChannelEvent += 
                new HandyLogic.UserJoinEventHandler(handyLogic_UserJoinChannelEvent);
            handyLogic.UserLeaveChannelEvent += 
                new HandyLogic.UserLeaveEventHandler(handyLogic_UserLeaveChannelEvent);
            handyLogic.UserRenameEvent += 
                new HandyLogic.UserRenameEventHandler(handyLogic_UserRenameEvent);
            handyLogic.PrivateObjectCreatedEvent += 
                new HandyLogic.PrivateObjectCreatedEventHandler(handyLogic_PrivateObjectCreatedEvent);
        }

        #endregion

        #region Custom initialization

        private void CustomInitialize()
        {
            InitializeRootNode();

            treeView.TreeViewNodeSorter = new NodeSorter();
            treeView.NodeMouseDoubleClick +=
                new TreeNodeMouseClickEventHandler(treeView_NodeMouseDoubleClick);
        }

        private void InitializeRootNode()
        {
            TreeNode channelsNode = new TreeNode();

            channelsNode.Name = "ChannelsNode";
            channelsNode.Text = "Channels";
            channelsNode.NodeFont =
                new Font("Microsoft Sans Serif", 8, FontStyle.Bold);
            channelsNode.Expand();

            treeView.Nodes.Add(channelsNode);
        }

        #endregion

        #region Overrides

        protected override void OnClosing(CancelEventArgs e)
        {
            handyLogic.Options.MainWindowState.LocX = this.Location.X;
            handyLogic.Options.MainWindowState.LocY = this.Location.Y;
            handyLogic.Options.MainWindowState.SizeX = this.Size.Width;
            handyLogic.Options.MainWindowState.SizeY = this.Size.Height;

            HandyLogic.ReleaseInstance();

            base.OnClosing(e);
        }

        protected override void OnCreateControl()
        {
            int x = handyLogic.Options.MainWindowState.LocX;
            int y = handyLogic.Options.MainWindowState.LocY;
            int size_x = handyLogic.Options.MainWindowState.SizeX;
            int size_y = handyLogic.Options.MainWindowState.SizeY;

            this.SetBounds(x, y, size_x, size_y);
            this.WindowState = FormWindowState.Normal;

 	        base.OnCreateControl();
        }

        #endregion

        #region Menu event handlers

        private void connectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            connectThread = new Thread(new ThreadStart(Connect));
            connectThread.Start();
        }

        private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (handyLogic.IsConnected)
            {
                handyLogic.Disconnect();
            }
        }

        private void joinToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (handyLogic.IsConnected)
            {
                JoinChannelForm joinChannelForm = new JoinChannelForm();
                if (joinChannelForm.ShowDialog() == DialogResult.OK)
                {
                    handyLogic.JoinChannel(joinChannelForm.ChannelName);
                }
            }
        }

        private void leaveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (handyLogic.IsConnected)
            {
                string[] channels = new string [handyLogic.Channels.Count];

                for (int i = 0; i < channels.Length; i++)
                {
                    channels[i] = handyLogic.Channels[i].Channel;
                }

                LeaveChannelForm leaveChannelForm = new LeaveChannelForm(channels);
                leaveChannelForm.ShowDialog();

                handyLogic.LeaveChannel(leaveChannelForm.SelectedChannelName);
            }
        }

        private void optionsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            OptionsForm form = new OptionsForm(handyLogic.Options);
            if (form.ShowDialog() == DialogResult.OK)
                handyLogic.Options.Save();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // todo: implement
        }

        private void consoleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (handyLogic.IsConnected)
            {
                ConsoleForm console = new ConsoleForm(handyLogic);
                console.Show();
            }
            else
            {
                MessageBox.Show("Can't open console window. Connect to server first.",
                                "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion

        #region Methods

        private void Connect()
        {
            if (!handyLogic.IsConnected)
            {
                handyLogic.Connect();
            }
        }

        private ContextMenu CreateChannelContextMenu(string channelName)
        {
            ContextMenu contextMenu = new ContextMenu();

            contextMenu.Name = channelName + "ContextMenu";

            MenuItem item1 = new MenuItem("Open Channel Window");
            MenuItem item2 = new MenuItem("Leave Channel");

            item1.Click += new EventHandler(OnOpenChannelWindow);
            item2.Click += new EventHandler(OnLeaveChannel);

            contextMenu.MenuItems.Add(item1);
            contextMenu.MenuItems.Add(item2);

            return contextMenu;
        }

        private ContextMenu CreatePrivateContextMenu(string userName)
        {
            ContextMenu contextMenu = new ContextMenu();

            contextMenu.Name = userName + "ContextMenu";

            MenuItem item = new MenuItem("Open Private Window");

            item.Click += new EventHandler(OnOpenPrivateWindow);

            contextMenu.MenuItems.Add(item);

            return contextMenu;
        }

        private void OnLeaveChannel(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(MenuItem))
            {
                MenuItem item = (MenuItem)sender;
                string contextMenuName = item.GetContextMenu().Name;
                string channelName = 
                    contextMenuName.Substring(0, contextMenuName.IndexOf("ContextMenu"));

                handyLogic.LeaveChannel(channelName);
            }
        }

        private void OnOpenChannelWindow(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(MenuItem))
            {
                MenuItem item = (MenuItem)sender;
                string contextMenuName = item.GetContextMenu().Name;
                string channelName =
                    contextMenuName.Substring(0, contextMenuName.IndexOf("ContextMenu"));

                ShowChannelForm(channelName);
            }
        }

        private void OnOpenPrivateWindow(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(MenuItem))
            {
                MenuItem item = (MenuItem)sender;
                string contextMenuName = item.GetContextMenu().Name;
                string userName =
                    contextMenuName.Substring(0, contextMenuName.IndexOf("ContextMenu"));

                PrivateObject obj = handyLogic.GetPrivateObject(userName);
                if (obj == null)
                {
                    handyLogic.CreatePrivateObject(userName, null);
                }
                else
                    ShowPrivateForm(userName);
            }
        }

        private void JoinChannel(string channelName)
        {
            if (this.treeView.InvokeRequired)
            {
                JoinChannelDelegate d = new JoinChannelDelegate(JoinChannel);
                this.Invoke(d, new object[] { channelName });
            }
            else
            {
                TreeNode channelNode = new TreeNode();

                channelNode.Name = channelName + "Node";
                channelNode.Text = channelName;
                channelNode.NodeFont =
                    new Font("Microsoft Sans Serif", 8, FontStyle.Underline);
                channelNode.Expand();
                channelNode.ContextMenu = CreateChannelContextMenu(channelName);

                treeView.Nodes["ChannelsNode"].Nodes.Add(channelNode);
            }
        }

        private void ShowChannelForm(string channelName)
        {
            ChannelObject obj =
                handyLogic.GetChannelObject(channelName);
            if (obj != null && obj.ChannelForm == null)
            {
                ChannelForm channelForm = new ChannelForm(handyLogic, obj);
                channelForm.Show();
            }
        }

        private void ShowPrivateForm(string userName)
        {
            PrivateObject obj =
                handyLogic.GetPrivateObject(userName);
            if (obj != null && obj.PrivateForm == null)
            {
                PrivateForm privateForm = new PrivateForm(handyLogic, obj);
                privateForm.Show();
            }
        }

        private void handyLogic_JoinChannelEvent(object sender, string channelName)
        {
            JoinChannel(channelName);

            if (this.InvokeRequired)
            {
                ShowChannelFormDelegate d = new ShowChannelFormDelegate(ShowChannelForm);
                this.Invoke(d, new object[] { channelName });
            }
            else
                ShowChannelForm(channelName);
        }

        private void LeaveChannel(string channelName)
        {
            if (this.treeView.InvokeRequired)
            {
                LeaveChannelDelegate d = new LeaveChannelDelegate(LeaveChannel);
                this.Invoke(d, new object[] { channelName });
            }
            else
            {
                TreeNode channelNode =
                    treeView.Nodes["ChannelsNode"].Nodes[channelName + "Node"];

                if (channelNode != null)
                {
                    channelNode.Remove();
                }
            }
        }

        private void handyLogic_LeaveChannelEvent(object sender, string channelName)
        {
            LeaveChannel(channelName);
        }

        private void handyLogic_UserLeaveChannelEvent(object sender, UserLeaveEventArgs e)
        {
            RemoveUser(e.UserName);
        }

        private void handyLogic_UserJoinChannelEvent(object sender, UserJoinEventArgs e)
        {
            AddUser(e.Channel, e.UserName);
        }

        private void handyLogic_UserRenameEvent(object sender, UserRenameEventArgs e)
        {
            RenameUser(e.UserOldName, e.UserNewName);
        }

        private void RemoveUser(string name)
        {
            if (this.treeView.InvokeRequired)
            {
                RemoveUserDelegate d = new RemoveUserDelegate(RemoveUser);
                this.Invoke(d, new object[] {name});
            }
            else
            {
                foreach (TreeNode channel in treeView.Nodes["ChannelsNode"].Nodes)
                {
                    if (channel.Nodes[name + "Node"] != null)
                        channel.Nodes[name + "Node"].Remove();
                }
            }
        }

        private void AddUser(string channel, string name)
        {
            if (this.treeView.InvokeRequired)
            {
                AddUserDelegate d = new AddUserDelegate(AddUser);
                this.Invoke(d, new object[] {channel, name});
            }
            else
            {
                if (treeView.Nodes["ChannelsNode"].Nodes[channel + "Node"] != null)
                {
                    TreeNode userNode = new TreeNode();

                    userNode.Name = name + "Node";
                    userNode.Text = name;
                    userNode.NodeFont =
                        new Font("Microsoft Sans Serif", 8, FontStyle.Regular);
                    userNode.ContextMenu = CreatePrivateContextMenu(name);

                    treeView.Nodes["ChannelsNode"].Nodes[channel + "Node"].Nodes.Add(userNode);
                }
            }
        }
        
        private void RenameUser(string oldName, string newName)
        {
            if (this.treeView.InvokeRequired)
            {
                RenameUserDelegate d = new RenameUserDelegate(RenameUser);
                this.Invoke(d, new object[] { oldName, newName });
            }
            else
            {
                foreach (TreeNode channel in treeView.Nodes["ChannelsNode"].Nodes)
                {
                    TreeNode node = channel.Nodes[oldName + "Node"];
                    if (node != null)
                    {
                        node.Name = newName + "Node";
                        node.Text = newName;
                    }
                }
            }
        }

        private void handyLogic_PrivateObjectCreatedEvent(object sender, string userName)
        {
            PrivateObject obj = handyLogic.GetPrivateObject(userName);
            obj.ShowPrivateFormEvent += new PrivateObject.ShowPrivateFormEventHandler(ShowPrivateFormEvent);

            if (this.InvokeRequired)
            {
                ShowPrivateFormDelegate d = new ShowPrivateFormDelegate(ShowPrivateForm);
                this.Invoke(d, new object[] { userName });
            }
            else
                ShowPrivateForm(userName);
        }

        private void ShowPrivateFormEvent(object sender, string userName)
        {
            if (this.InvokeRequired)
            {
                ShowPrivateFormDelegate d = new ShowPrivateFormDelegate(ShowPrivateForm);
                this.Invoke(d, new object[] { userName });
            }
            else
                ShowPrivateForm(userName);
        }

        private void treeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            TreeNode node = e.Node;
            if (node.Level == 1) // channel node
            {
                // todo: find later better way
                /*if (node.IsExpanded)
                    node.Collapse(true);
                else
                    node.Expand();

                string channelName =
                    node.Name.Substring(0, node.Name.IndexOf("Node"));

                ShowChannelForm(channelName);*/
            }
            else if (node.Level == 2) // user node
            {
                string userName =
                    node.Name.Substring(0, node.Name.IndexOf("Node"));

                PrivateObject obj = handyLogic.GetPrivateObject(userName);
                if (obj == null)
                {
                    handyLogic.CreatePrivateObject(userName, null);
                }
                else
                    ShowPrivateForm(userName);
            }
        }

        #endregion
    }
}
